Overview

Details on the construction of the MedStar EPCR Patient symptom table. 126 unique symptoms were recorded for 2853 calls. A total of 4086 symptoms were recorded among the calls.

Load packages and data

library(tidyverse)
library(bfuncs)
symptoms <- feather::read_feather("/Users/jaredwiegand/Desktop/DETECT Repository/symptoms.feather")
  • Adding file path for DETECT data server.
  • Brad emailed Chris Harvey on 2019-02-11 to make Jared an authorized user.
symptoms <- feather::read_feather("/Volumes/DETECT/one_year_data/symptoms.feather")
about_data(symptoms) # 28,228 observations and 2 variables
[1] "28,228 observations and 2 variables"

top

Simplify symptom list

Currently, the symptom list includes upper and lower case letters, spaces, and special characters. These are not characteristics we want on our variable names, and they make matching with regular expressions more difficult. We want to do both of those things below. So, here we will:

  • Convert all letters to lower case
  • Replace spaces with underscores
  • Replace parentheses with underscores
  • Replace periods with underscores
  • Replace commas with underscores
  • Replace all instances of 2 or more consecutive underscores we created in the process with single underscores
  • Remove trailing underscores
simplify_symptom_strings <- function(x) {
  x %>% 
    tolower() %>% 
    stringr::str_replace_all(pattern = "\\s", replacement = "_") %>% # white space
    stringr::str_replace_all(pattern = "[\\(|\\)]", replacement = "_") %>% # parentheses
    stringr::str_replace_all(pattern = "\\.", replacement = "_") %>% # periods
    stringr::str_replace_all(pattern = "\\,(?=\\_)", replacement = "_") %>% # commas - not separating symptoms
    stringr::str_replace_all(pattern = "\\_{2,}", replacement = "_") %>% # multiple underscores
    stringr::str_replace_all(pattern = "\\_(?=\\')", replacement = "") # trailing underscores
}
symptoms <- symptoms %>% 
  mutate(symptoms_simplified = simplify_symptom_strings(symptoms))
about_data(symptoms) # 28,228 observations and 3 variables
[1] "28,228 observations and 3 variables"

top

Find all symptoms

  • Figure out how to break character stings into component symptoms
  • Get list of all unique symptoms
  • Turn symptoms into binary variables
  • Create new table of symptoms
  • Create two-way table of symptoms by incident complaint

Create List of Unique Symptoms

symptom_list <- symptoms %>% 
  filter(!is.na(symptoms_simplified)) %>% # Remove NA
  pull(symptoms_simplified) %>% # Coerce to vector 
  unique() %>% # Gets unique groups of symptoms
  stringr::str_split(pattern = "'',''") %>% # Splits character string at '',''
  unlist() %>% # Coerce from list to vector
  stringr::str_remove_all("'") %>% # Remove remaining single quotes
  unique() # Get unique symptoms

Create dummy variables for each symptom, by the same name

for (i in seq_along(symptom_list)) {
  symptoms[symptom_list[i]] <- NA
}
rm(i)
about_data(symptoms) # 28,228 observations and 129 variables
[1] "28,228 observations and 129 variables"

Assign values for each symptom dummy variable

for (i in seq_along(symptom_list)) {
  # For each variable in symptoms that shares the name of the i'th value in symptom_list
  symptoms[symptom_list[i]] <- if_else( 
    # If the name of the variable is found anywhere in symptoms_simplified
    # Set the value of that variable to 1 in that row
    # Otherwise set it to 0
    stringr::str_detect(
      string = symptoms$symptoms_simplified, 
      pattern = symptom_list[i]
    ), 1, 0
  )
}
rm(i)
about_data(symptoms) # 28,228 observations and 129 variables
[1] "28,228 observations and 129 variables"

top

Frequency Tables

Incident complaints

In descending order of occurrence

Incident symptoms

In descending order of occurrence

Cross Tabulation of Incident Complaint by Symptoms

This table is so large that it is difficult to digest. Let’s make a heat map

top

Heat maps

Reorient the table above so that each row is a combination of incident complaint and symptom

complaint_symptoms_cross_gathered <- complaint_symptoms_cross %>% 
  
  # Gather symptom columns for heatmap
  group_by(incident_complaint) %>% 
  gather(key = symptom, value = n, -incident_complaint) %>% 
  
  # Make the symptoms shorter/easier to read by removing everything
  # including and after "_r53_1, _k59_00, etc."
  mutate(symptom_short = stringr::str_replace_all(
    string = symptom,
    pattern = "_[a-z]\\d+\\S*",
    replacement = ''
  )) %>% 
  
  # Improve readability
  arrange(incident_complaint, desc(n)) %>% 
  select(incident_complaint, symptom_short, n) %>%  
  print()

Some incident complaints, no symptoms are ever recorded. They are:

 [1] "Animal Bite"                                                              
 [2] "Auto vs. Pedestrian"                                                      
 [3] "Cardiac Arrest - Possible DOA"                                            
 [4] "Drowning/Diving/SCUBA Accident"                                           
 [5] "Eye Problem/Injury"                                                       
 [6] "Industrial Accident/Inaccessible Incident/Other Entrapments (Non-Vehicle)"
 [7] "Invalid Assist/Lifting Assist"                                            
 [8] "Medical Alarm"                                                            
 [9] "Nausea/Vomiting"                                                          
[10] "Pain"                                                                     
[11] "Unresponsive"                                                             

We will drop these incident complaints from the data becasue they will add no information to the heatmaps below.

complaint_symptoms_cross_gathered <- complaint_symptoms_cross_gathered %>% 
  mutate(cum_n = max(cumsum(n))) %>% 
  filter(cum_n > 0)

Absolute occurrence

Here we are plotting the number of times that given compliant/symptom pair occurred in the data.

complaint_symptoms_heatmap <- complaint_symptoms_cross_gathered %>% 
  ggplot() +
    geom_tile(aes(incident_complaint, symptom_short, fill = n)) + 
    theme(
      axis.text.y = element_text(size = 9),
      axis.text.x = element_text(size = 10, hjust = 1, vjust = 0.5, angle = 90)
    )

Hard to read in this limited space.
* Save as image file.
* Add image to the html page

ggsave(
  filename = "fig_complain_symptom_heatmap.png",
  plot = complaint_symptoms_heatmap,
  device = "png",
  path = "../images",
  width = 15,
  height = 20,
  units = "in"
)

Relative observation of symptoms

For each incident complaint, what was the proportion of times a given symptom was recorded when any symptoms were recorded?

relative_symptoms_heatmap <- complaint_symptoms_cross_gathered %>% 
  # Calculate propotions
  mutate(
    prop = n / max(cumsum(n))
  ) %>% 
  
  # Plot heatmap
  ggplot() +
    geom_tile(aes(incident_complaint, symptom_short, fill = prop)) +
    theme(
      axis.text.y = element_text(size = 9),
      axis.text.x = element_text(size = 10, hjust = 1, vjust = 0.5, angle = 90)
    )

Hard to read in this limited space.
* Save as image file.
* Add image to the html page

ggsave(
  filename = "fig_relative_symptoms_heatmap.png",
  plot = relative_symptoms_heatmap,
  device = "png",
  path = "../images",
  width = 15,
  height = 20,
  units = "in"
)

top

Session information

R version 3.5.1 (2018-07-02)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS  10.14.3

Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] bindrcpp_0.2.2  bfuncs_0.2.1    forcats_0.3.0   stringr_1.3.1   dplyr_0.7.8     purrr_0.2.5    
 [7] readr_1.2.1     tidyr_0.8.2     tibble_1.4.2    ggplot2_3.1.0   tidyverse_1.2.1 packrat_0.4.9-3

loaded via a namespace (and not attached):
 [1] tidyselect_0.2.5 haven_2.0.0      lattice_0.20-35  colorspace_1.3-2 generics_0.0.2   htmltools_0.3.6 
 [7] yaml_2.2.0       base64enc_0.1-3  utf8_1.1.4       rlang_0.3.0.1    later_0.7.5      pillar_1.3.0    
[13] glue_1.3.0       withr_2.1.2      modelr_0.1.2     readxl_1.1.0     bindr_0.1.1      plyr_1.8.4      
[19] munsell_0.5.0    gtable_0.2.0     cellranger_1.1.0 rvest_0.3.2      htmlwidgets_1.3  evaluate_0.12   
[25] labeling_0.3     knitr_1.20       httpuv_1.4.5     crosstalk_1.0.0  fansi_0.4.0      broom_0.5.1     
[31] Rcpp_1.0.0       xtable_1.8-3     promises_1.0.1   DT_0.5           scales_1.0.0     backports_1.1.2 
[37] feather_0.3.1    jsonlite_1.5     mime_0.6         hms_0.4.2        digest_0.6.18    stringi_1.2.4   
[43] shiny_1.2.0      grid_3.5.1       rprojroot_1.3-2  cli_1.0.1        tools_3.5.1      magrittr_1.5    
[49] lazyeval_0.2.1   crayon_1.3.4     pkgconfig_2.0.2  xml2_1.2.0       lubridate_1.7.4  assertthat_0.2.0
[55] rmarkdown_1.10   httr_1.3.1       rstudioapi_0.8   R6_2.3.0         nlme_3.1-137     compiler_3.5.1  
LS0tCnRpdGxlOiAiQ3JlYXRpbmcgUGF0aWVudCBTeW1wdG9tIFRhYmxlIgpkYXRlOiAiQ3JlYXRlZDogMjAxOS0wMS0zMSA8YnI+IFVwZGF0ZWQ6IGByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY3NzOiBjdXN0b20tY3NzLmNzcwotLS0KCiMgT3ZlcnZpZXcKCkRldGFpbHMgb24gdGhlIGNvbnN0cnVjdGlvbiBvZiB0aGUgTWVkU3RhciBFUENSIFBhdGllbnQgc3ltcHRvbSB0YWJsZS4gICAxMjYgdW5pcXVlIHN5bXB0b21zIHdlcmUgcmVjb3JkZWQgZm9yIDI4NTMgY2FsbHMuICBBIHRvdGFsIG9mIDQwODYgc3ltcHRvbXMgd2VyZSByZWNvcmRlZCBhbW9uZyB0aGUgY2FsbHMuCgoKIyBMb2FkIHBhY2thZ2VzIGFuZCBkYXRhCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGNvbW1lbnQgPSBOQSkKU3lzLnNldGVudihUWiA9ICJVUy9DZW50cmFsIikKYGBgCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShiZnVuY3MpCmBgYAoKYGBge3IgZXZhbD1GQUxTRX0Kc3ltcHRvbXMgPC0gZmVhdGhlcjo6cmVhZF9mZWF0aGVyKCIvVXNlcnMvamFyZWR3aWVnYW5kL0Rlc2t0b3AvREVURUNUIFJlcG9zaXRvcnkvc3ltcHRvbXMuZmVhdGhlciIpCmBgYAoKKiBBZGRpbmcgZmlsZSBwYXRoIGZvciBERVRFQ1QgZGF0YSBzZXJ2ZXIuICAgIAoqIEJyYWQgZW1haWxlZCBDaHJpcyBIYXJ2ZXkgb24gMjAxOS0wMi0xMSB0byBtYWtlIEphcmVkIGFuIGF1dGhvcml6ZWQgdXNlci4KCmBgYHtyfQpzeW1wdG9tcyA8LSBmZWF0aGVyOjpyZWFkX2ZlYXRoZXIoIi9Wb2x1bWVzL0RFVEVDVC9vbmVfeWVhcl9kYXRhL3N5bXB0b21zLmZlYXRoZXIiKQpgYGAKCmBgYHtyfQphYm91dF9kYXRhKHN5bXB0b21zKSAjIDI4LDIyOCBvYnNlcnZhdGlvbnMgYW5kIDIgdmFyaWFibGVzCmBgYAoKW3RvcF0oI3RvcCkKCgoKCgoKCgoKCiMgU2ltcGxpZnkgc3ltcHRvbSBsaXN0CgpDdXJyZW50bHksIHRoZSBzeW1wdG9tIGxpc3QgaW5jbHVkZXMgdXBwZXIgYW5kIGxvd2VyIGNhc2UgbGV0dGVycywgc3BhY2VzLCBhbmQgc3BlY2lhbCBjaGFyYWN0ZXJzLiBUaGVzZSBhcmUgbm90IGNoYXJhY3RlcmlzdGljcyB3ZSB3YW50IG9uIG91ciB2YXJpYWJsZSBuYW1lcywgYW5kIHRoZXkgbWFrZSBtYXRjaGluZyB3aXRoIHJlZ3VsYXIgZXhwcmVzc2lvbnMgbW9yZSBkaWZmaWN1bHQuIFdlIHdhbnQgdG8gZG8gYm90aCBvZiB0aG9zZSB0aGluZ3MgYmVsb3cuIFNvLCBoZXJlIHdlIHdpbGw6CgoqIENvbnZlcnQgYWxsIGxldHRlcnMgdG8gbG93ZXIgY2FzZSAgIAoqIFJlcGxhY2Ugc3BhY2VzIHdpdGggdW5kZXJzY29yZXMgICAKKiBSZXBsYWNlIHBhcmVudGhlc2VzIHdpdGggdW5kZXJzY29yZXMgICAKKiBSZXBsYWNlIHBlcmlvZHMgd2l0aCB1bmRlcnNjb3JlcyAgCiogUmVwbGFjZSBjb21tYXMgd2l0aCB1bmRlcnNjb3JlcyAgCiogUmVwbGFjZSBhbGwgaW5zdGFuY2VzIG9mIDIgb3IgbW9yZSBjb25zZWN1dGl2ZSB1bmRlcnNjb3JlcyB3ZSBjcmVhdGVkIGluIHRoZSBwcm9jZXNzIHdpdGggc2luZ2xlIHVuZGVyc2NvcmVzICAgCiogUmVtb3ZlIHRyYWlsaW5nIHVuZGVyc2NvcmVzICAgCgpgYGB7cn0Kc2ltcGxpZnlfc3ltcHRvbV9zdHJpbmdzIDwtIGZ1bmN0aW9uKHgpIHsKICB4ICU+JSAKICAgIHRvbG93ZXIoKSAlPiUgCiAgICBzdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwocGF0dGVybiA9ICJcXHMiLCByZXBsYWNlbWVudCA9ICJfIikgJT4lICMgd2hpdGUgc3BhY2UKICAgIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbChwYXR0ZXJuID0gIltcXCh8XFwpXSIsIHJlcGxhY2VtZW50ID0gIl8iKSAlPiUgIyBwYXJlbnRoZXNlcwogICAgc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKHBhdHRlcm4gPSAiXFwuIiwgcmVwbGFjZW1lbnQgPSAiXyIpICU+JSAjIHBlcmlvZHMKICAgIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbChwYXR0ZXJuID0gIlxcLCg/PVxcXykiLCByZXBsYWNlbWVudCA9ICJfIikgJT4lICMgY29tbWFzIC0gbm90IHNlcGFyYXRpbmcgc3ltcHRvbXMKICAgIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbChwYXR0ZXJuID0gIlxcX3syLH0iLCByZXBsYWNlbWVudCA9ICJfIikgJT4lICMgbXVsdGlwbGUgdW5kZXJzY29yZXMKICAgIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbChwYXR0ZXJuID0gIlxcXyg/PVxcJykiLCByZXBsYWNlbWVudCA9ICIiKSAjIHRyYWlsaW5nIHVuZGVyc2NvcmVzCn0KYGBgCgpgYGB7cn0Kc3ltcHRvbXMgPC0gc3ltcHRvbXMgJT4lIAogIG11dGF0ZShzeW1wdG9tc19zaW1wbGlmaWVkID0gc2ltcGxpZnlfc3ltcHRvbV9zdHJpbmdzKHN5bXB0b21zKSkKYGBgCgpgYGB7cn0KYWJvdXRfZGF0YShzeW1wdG9tcykgIyAyOCwyMjggb2JzZXJ2YXRpb25zIGFuZCAzIHZhcmlhYmxlcwpgYGAKClt0b3BdKCN0b3ApCgoKCgoKCgoKCgojIEZpbmQgYWxsIHN5bXB0b21zCgoqIEZpZ3VyZSBvdXQgaG93IHRvIGJyZWFrIGNoYXJhY3RlciBzdGluZ3MgaW50byBjb21wb25lbnQgc3ltcHRvbXMgICAKKiBHZXQgbGlzdCBvZiBhbGwgdW5pcXVlIHN5bXB0b21zICAgCiogVHVybiBzeW1wdG9tcyBpbnRvIGJpbmFyeSB2YXJpYWJsZXMgICAKKiBDcmVhdGUgbmV3IHRhYmxlIG9mIHN5bXB0b21zICAgCiogQ3JlYXRlIHR3by13YXkgdGFibGUgb2Ygc3ltcHRvbXMgYnkgaW5jaWRlbnQgY29tcGxhaW50ICAgCgoKIyMgQ3JlYXRlIExpc3Qgb2YgVW5pcXVlIFN5bXB0b21zCgpgYGB7cn0Kc3ltcHRvbV9saXN0IDwtIHN5bXB0b21zICU+JSAKICBmaWx0ZXIoIWlzLm5hKHN5bXB0b21zX3NpbXBsaWZpZWQpKSAlPiUgIyBSZW1vdmUgTkEKICBwdWxsKHN5bXB0b21zX3NpbXBsaWZpZWQpICU+JSAjIENvZXJjZSB0byB2ZWN0b3IgCiAgdW5pcXVlKCkgJT4lICMgR2V0cyB1bmlxdWUgZ3JvdXBzIG9mIHN5bXB0b21zCiAgc3RyaW5ncjo6c3RyX3NwbGl0KHBhdHRlcm4gPSAiJycsJyciKSAlPiUgIyBTcGxpdHMgY2hhcmFjdGVyIHN0cmluZyBhdCAnJywnJwogIHVubGlzdCgpICU+JSAjIENvZXJjZSBmcm9tIGxpc3QgdG8gdmVjdG9yCiAgc3RyaW5ncjo6c3RyX3JlbW92ZV9hbGwoIiciKSAlPiUgIyBSZW1vdmUgcmVtYWluaW5nIHNpbmdsZSBxdW90ZXMKICB1bmlxdWUoKSAjIEdldCB1bmlxdWUgc3ltcHRvbXMKYGBgCgoKIyMgQ3JlYXRlIGR1bW15IHZhcmlhYmxlcyBmb3IgZWFjaCBzeW1wdG9tLCBieSB0aGUgc2FtZSBuYW1lCgpgYGB7cn0KZm9yIChpIGluIHNlcV9hbG9uZyhzeW1wdG9tX2xpc3QpKSB7CiAgc3ltcHRvbXNbc3ltcHRvbV9saXN0W2ldXSA8LSBOQQp9CnJtKGkpCmBgYAoKYGBge3J9CmFib3V0X2RhdGEoc3ltcHRvbXMpICMgMjgsMjI4IG9ic2VydmF0aW9ucyBhbmQgMTI5IHZhcmlhYmxlcwpgYGAKCgojIyBBc3NpZ24gdmFsdWVzIGZvciBlYWNoIHN5bXB0b20gZHVtbXkgdmFyaWFibGUKCmBgYHtyfQpmb3IgKGkgaW4gc2VxX2Fsb25nKHN5bXB0b21fbGlzdCkpIHsKICAjIEZvciBlYWNoIHZhcmlhYmxlIGluIHN5bXB0b21zIHRoYXQgc2hhcmVzIHRoZSBuYW1lIG9mIHRoZSBpJ3RoIHZhbHVlIGluIHN5bXB0b21fbGlzdAogIHN5bXB0b21zW3N5bXB0b21fbGlzdFtpXV0gPC0gaWZfZWxzZSggCiAgICAjIElmIHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZSBpcyBmb3VuZCBhbnl3aGVyZSBpbiBzeW1wdG9tc19zaW1wbGlmaWVkCiAgICAjIFNldCB0aGUgdmFsdWUgb2YgdGhhdCB2YXJpYWJsZSB0byAxIGluIHRoYXQgcm93CiAgICAjIE90aGVyd2lzZSBzZXQgaXQgdG8gMAogICAgc3RyaW5ncjo6c3RyX2RldGVjdCgKICAgICAgc3RyaW5nID0gc3ltcHRvbXMkc3ltcHRvbXNfc2ltcGxpZmllZCwgCiAgICAgIHBhdHRlcm4gPSBzeW1wdG9tX2xpc3RbaV0KICAgICksIDEsIDAKICApCn0Kcm0oaSkKYGBgCgpgYGB7cn0KYWJvdXRfZGF0YShzeW1wdG9tcykgIyAyOCwyMjggb2JzZXJ2YXRpb25zIGFuZCAxMjkgdmFyaWFibGVzCmBgYAoKW3RvcF0oI3RvcCkKCgoKCgoKCgoKCiMgRnJlcXVlbmN5IFRhYmxlcwoKCiMjIEluY2lkZW50IGNvbXBsYWludHMKCkluIGRlc2NlbmRpbmcgb3JkZXIgb2Ygb2NjdXJyZW5jZQoKYGBge3IgZWNobz1GQUxTRX0Kc3ltcHRvbXMgJT4lIAogIGdyb3VwX2J5KGluY2lkZW50X2NvbXBsYWludCkgJT4lIAogIHN1bW1hcmlzZShuID0gbigpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBhcnJhbmdlKGRlc2MobikpICU+JSAKICBtdXRhdGUocGVyY2VudCA9IG4gLyBtYXgoY3Vtc3VtKG4pKSAqIDEwMCkKYGBgCgoKIyMgSW5jaWRlbnQgc3ltcHRvbXMKCkluIGRlc2NlbmRpbmcgb3JkZXIgb2Ygb2NjdXJyZW5jZQoKYGBge3IgZWNobz1GQUxTRX0Kc3ltcHRvbXMgJT4lIAogIHNlbGVjdCgtaW5jaWRlbnRfY29tcGxhaW50LCAtc3ltcHRvbXMsIC1zeW1wdG9tc19zaW1wbGlmaWVkKSAlPiUgCiAgc3VtbWFyaXNlX2FsbChmdW5zKHN1bSguLCBuYS5ybSA9IFRSVUUpKSkgJT4lIAogIHRpZHlyOjpnYXRoZXIoa2V5ID0gInN5bXB0b20iLCB2YWx1ZSA9ICJuIikgJT4lIAogIGFycmFuZ2UoZGVzYyhuKSkgJT4lIAogIG11dGF0ZShwZXJjZW50ID0gbiAvIG1heChjdW1zdW0obikpICogMTAwKQpgYGAKCgojIyBDcm9zcyBUYWJ1bGF0aW9uIG9mIEluY2lkZW50IENvbXBsYWludCBieSBTeW1wdG9tcwoKYGBge3IgZWNobz1GQUxTRX0KY29tcGxhaW50X3N5bXB0b21zX2Nyb3NzIDwtIHN5bXB0b21zICU+JSAKICBzZWxlY3QoLXN5bXB0b21zLCAtc3ltcHRvbXNfc2ltcGxpZmllZCkgJT4lIAogIGdyb3VwX2J5KGluY2lkZW50X2NvbXBsYWludCkgJT4lIAogIHN1bW1hcmlzZV9pZigKICAgIC5wcmVkaWNhdGUgPSBpcy5udW1lcmljLAogICAgLmZ1bnMgPSBmdW5zKHN1bSguLCBuYS5ybSA9IFRSVUUpKQogICkgJT4lIAogIHByaW50KCkKYGBgCgpUaGlzIHRhYmxlIGlzIHNvIGxhcmdlIHRoYXQgaXQgaXMgZGlmZmljdWx0IHRvIGRpZ2VzdC4gTGV0J3MgbWFrZSBhIGhlYXQgbWFwCgpbdG9wXSgjdG9wKQoKCgoKCgoKCgoKIyBIZWF0IG1hcHMKClJlb3JpZW50IHRoZSB0YWJsZSBhYm92ZSBzbyB0aGF0IGVhY2ggcm93IGlzIGEgY29tYmluYXRpb24gb2YgaW5jaWRlbnQgY29tcGxhaW50IGFuZCBzeW1wdG9tCgpgYGB7cn0KY29tcGxhaW50X3N5bXB0b21zX2Nyb3NzX2dhdGhlcmVkIDwtIGNvbXBsYWludF9zeW1wdG9tc19jcm9zcyAlPiUgCiAgCiAgIyBHYXRoZXIgc3ltcHRvbSBjb2x1bW5zIGZvciBoZWF0bWFwCiAgZ3JvdXBfYnkoaW5jaWRlbnRfY29tcGxhaW50KSAlPiUgCiAgZ2F0aGVyKGtleSA9IHN5bXB0b20sIHZhbHVlID0gbiwgLWluY2lkZW50X2NvbXBsYWludCkgJT4lIAogIAogICMgTWFrZSB0aGUgc3ltcHRvbXMgc2hvcnRlci9lYXNpZXIgdG8gcmVhZCBieSByZW1vdmluZyBldmVyeXRoaW5nCiAgIyBpbmNsdWRpbmcgYW5kIGFmdGVyICJfcjUzXzEsIF9rNTlfMDAsIGV0Yy4iCiAgbXV0YXRlKHN5bXB0b21fc2hvcnQgPSBzdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoCiAgICBzdHJpbmcgPSBzeW1wdG9tLAogICAgcGF0dGVybiA9ICJfW2Etel1cXGQrXFxTKiIsCiAgICByZXBsYWNlbWVudCA9ICcnCiAgKSkgJT4lIAogIAogICMgSW1wcm92ZSByZWFkYWJpbGl0eQogIGFycmFuZ2UoaW5jaWRlbnRfY29tcGxhaW50LCBkZXNjKG4pKSAlPiUgCiAgc2VsZWN0KGluY2lkZW50X2NvbXBsYWludCwgc3ltcHRvbV9zaG9ydCwgbikgJT4lICAKICBwcmludCgpCmBgYAoKU29tZSBpbmNpZGVudCBjb21wbGFpbnRzLCBubyBzeW1wdG9tcyBhcmUgZXZlciByZWNvcmRlZC4gVGhleSBhcmU6CgpgYGB7ciBlY2hvPUZBTFNFfQpjb21wbGFpbnRfc3ltcHRvbXNfY3Jvc3NfZ2F0aGVyZWQgJT4lIAogIG11dGF0ZShjdW1fbiA9IG1heChjdW1zdW0obikpKSAlPiUgCiAgZmlsdGVyKGN1bV9uID09IDApICU+JSAKICBwdWxsKGluY2lkZW50X2NvbXBsYWludCkgJT4lIAogIHVuaXF1ZSgpCmBgYAoKV2Ugd2lsbCBkcm9wIHRoZXNlIGluY2lkZW50IGNvbXBsYWludHMgZnJvbSB0aGUgZGF0YSBiZWNhc3VlIHRoZXkgd2lsbCBhZGQgbm8gaW5mb3JtYXRpb24gdG8gdGhlIGhlYXRtYXBzIGJlbG93LgoKYGBge3J9CmNvbXBsYWludF9zeW1wdG9tc19jcm9zc19nYXRoZXJlZCA8LSBjb21wbGFpbnRfc3ltcHRvbXNfY3Jvc3NfZ2F0aGVyZWQgJT4lIAogIG11dGF0ZShjdW1fbiA9IG1heChjdW1zdW0obikpKSAlPiUgCiAgZmlsdGVyKGN1bV9uID4gMCkKYGBgCgoKIyMgQWJzb2x1dGUgb2NjdXJyZW5jZQoKSGVyZSB3ZSBhcmUgcGxvdHRpbmcgdGhlIG51bWJlciBvZiB0aW1lcyB0aGF0IGdpdmVuIGNvbXBsaWFudC9zeW1wdG9tIHBhaXIgb2NjdXJyZWQgaW4gdGhlIGRhdGEuCgpgYGB7cn0KY29tcGxhaW50X3N5bXB0b21zX2hlYXRtYXAgPC0gY29tcGxhaW50X3N5bXB0b21zX2Nyb3NzX2dhdGhlcmVkICU+JSAKICBnZ3Bsb3QoKSArCiAgICBnZW9tX3RpbGUoYWVzKGluY2lkZW50X2NvbXBsYWludCwgc3ltcHRvbV9zaG9ydCwgZmlsbCA9IG4pKSArIAogICAgdGhlbWUoCiAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBoanVzdCA9IDEsIHZqdXN0ID0gMC41LCBhbmdsZSA9IDkwKQogICAgKQpgYGAKCkhhcmQgdG8gcmVhZCBpbiB0aGlzIGxpbWl0ZWQgc3BhY2UuICAgIAoqIFNhdmUgYXMgaW1hZ2UgZmlsZS4gICAKKiBBZGQgaW1hZ2UgdG8gdGhlIGh0bWwgcGFnZSAgIAoKYGBge3J9Cmdnc2F2ZSgKICBmaWxlbmFtZSA9ICJmaWdfY29tcGxhaW5fc3ltcHRvbV9oZWF0bWFwLnBuZyIsCiAgcGxvdCA9IGNvbXBsYWludF9zeW1wdG9tc19oZWF0bWFwLAogIGRldmljZSA9ICJwbmciLAogIHBhdGggPSAiLi4vaW1hZ2VzIiwKICB3aWR0aCA9IDE1LAogIGhlaWdodCA9IDIwLAogIHVuaXRzID0gImluIgopCmBgYAoKIVtdKC4uL2ltYWdlcy9maWdfY29tcGxhaW5fc3ltcHRvbV9oZWF0bWFwLnBuZykKCgojIyBSZWxhdGl2ZSBvYnNlcnZhdGlvbiBvZiBzeW1wdG9tcwoKRm9yIGVhY2ggaW5jaWRlbnQgY29tcGxhaW50LCB3aGF0IHdhcyB0aGUgcHJvcG9ydGlvbiBvZiB0aW1lcyBhIGdpdmVuIHN5bXB0b20gd2FzIHJlY29yZGVkIHdoZW4gYW55IHN5bXB0b21zIHdlcmUgcmVjb3JkZWQ/CgpgYGB7cn0KcmVsYXRpdmVfc3ltcHRvbXNfaGVhdG1hcCA8LSBjb21wbGFpbnRfc3ltcHRvbXNfY3Jvc3NfZ2F0aGVyZWQgJT4lIAoKICAjIENhbGN1bGF0ZSBwcm9wb3Rpb25zCiAgbXV0YXRlKAogICAgcHJvcCA9IG4gLyBtYXgoY3Vtc3VtKG4pKQogICkgJT4lIAogIAogICMgUGxvdCBoZWF0bWFwCiAgZ2dwbG90KCkgKwogICAgZ2VvbV90aWxlKGFlcyhpbmNpZGVudF9jb21wbGFpbnQsIHN5bXB0b21fc2hvcnQsIGZpbGwgPSBwcm9wKSkgKwogICAgdGhlbWUoCiAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBoanVzdCA9IDEsIHZqdXN0ID0gMC41LCBhbmdsZSA9IDkwKQogICAgKQpgYGAKCkhhcmQgdG8gcmVhZCBpbiB0aGlzIGxpbWl0ZWQgc3BhY2UuICAgIAoqIFNhdmUgYXMgaW1hZ2UgZmlsZS4gICAKKiBBZGQgaW1hZ2UgdG8gdGhlIGh0bWwgcGFnZSAgIAoKYGBge3J9Cmdnc2F2ZSgKICBmaWxlbmFtZSA9ICJmaWdfcmVsYXRpdmVfc3ltcHRvbXNfaGVhdG1hcC5wbmciLAogIHBsb3QgPSByZWxhdGl2ZV9zeW1wdG9tc19oZWF0bWFwLAogIGRldmljZSA9ICJwbmciLAogIHBhdGggPSAiLi4vaW1hZ2VzIiwKICB3aWR0aCA9IDE1LAogIGhlaWdodCA9IDIwLAogIHVuaXRzID0gImluIgopCmBgYAoKIVtdKC4uL2ltYWdlcy9maWdfcmVsYXRpdmVfc3ltcHRvbXNfaGVhdG1hcC5wbmcpCgpbdG9wXSgjdG9wKQoKCgoKCgoKCgoKIyBTZXNzaW9uIGluZm9ybWF0aW9uCgpgYGB7ciBlY2hvPUZBTFNFfQpybShsaXN0ID0gbHMoKSkKYGBgCgpgYGB7ciBlY2hvPUZBTFNFfQpzZXNzaW9uSW5mbygpCmBgYAoKPHNjcmlwdCBzcmM9InNjcmlwdC5qcyI+PC9zY3JpcHQ+